/*
 * Copyright (c) 2011-2018 Richard Braun.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <kern/init.h>
#include <machine/asm.h>
#include <machine/cpu.h>

#define CPU_RED_ZONE_SIZE 128

/*
 * Macro used to compute an offset, in bytes, between two indexes in a
 * low level exception frame. The indexes may be given in any order.
 */
#define CPU_LEF_OFFSET(index1, index2)   \
  (((index2) - (index1)) * CPU_WORD_SIZE)

.text

#ifdef __LP64__

/*
 * Number of CPU registers on exception.
 *
 * These are the registers automatically pushed by the CPU when an exception
 * is taken, including the error code.
 */
#define CPU_NR_CRE   (CPU_EXC_FRAME_SIZE - CPU_EXC_FRAME_ERROR)

/*
 * Remaining size when taking an exception.
 *
 * This is the total size of an exception frame without the registers
 * automatically pushed by the CPU and those saved for stack switching.
 */
#define CPU_LEF_EXC_REM   \
  CPU_LEF_OFFSET (CPU_EXC_FRAME_ERROR - 2, CPU_EXC_FRAME_SIZE)

// RSP offset, from the top of the exception frame.
#define CPU_LEF_RSP   CPU_LEF_OFFSET (CPU_EXC_FRAME_SIZE, CPU_EXC_FRAME_RSP)

/*
 * Offsets where registers used for stack switching are saved when taking
 * an exception, from the top of the exception frame.
 */
#define CPU_LEF_EXC_RAX   \
  CPU_LEF_OFFSET (CPU_EXC_FRAME_SIZE, CPU_EXC_FRAME_ERROR - 2)

#define CPU_LEF_EXC_RBX   \
  CPU_LEF_OFFSET (CPU_EXC_FRAME_SIZE, CPU_EXC_FRAME_ERROR - 1)

// Size used to store the vector and the error code.
#define CPU_LEF_VEC_ERR   \
  CPU_LEF_OFFSET (CPU_EXC_FRAME_VECTOR, CPU_EXC_FRAME_ERROR + 1)

.macro cpu_ll_exc_store_registers
  pushq %r15
  pushq %r14
  pushq %r13
  pushq %r12
  pushq %r11
  pushq %r10
  pushq %r9
  pushq %r8
  pushq %rdi
  pushq %rsi
  pushq %rbp
  pushq %rdx
  pushq %rcx
  pushq %rbx
  pushq %rax
.endm

.macro cpu_ll_exc_load_registers
  popq %rax
  popq %rbx
  popq %rcx
  popq %rdx
  popq %rbp
  popq %rsi
  popq %rdi
  popq %r8
  popq %r9
  popq %r10
  popq %r11
  popq %r12
  popq %r13
  popq %r14
  popq %r15
  addq $CPU_LEF_VEC_ERR, %rsp   // skip vector and error.
.endm

.macro cpu_ll_exc_push_word source offset buffer
  movq -\offset(\source), \buffer
  pushq \buffer
.endm

.macro cpu_ll_exc_push source nr_words buffer
.set offset, CPU_WORD_SIZE
.rept \nr_words
    cpu_ll_exc_push_word \source offset \buffer
.set offset, offset + CPU_WORD_SIZE
.endr
.endm

/*
 * Note that, unlike i386, the CPU aligns the stack frame to 16 bytes,
 * and skipping the red zone keeps the stack pointer correctly aligned.
 */
.macro cpu_ll_exc_enter vector
  pushq %rbx                               // save registers used for
  pushq %rax                               // stack switching.
  leaq CPU_LEF_EXC_REM(%rsp), %rbx         // point to exception frame top.
  movq CPU_LEF_RSP(%rbx), %rsp             // point to thread stack.
  subq $CPU_RED_ZONE_SIZE, %rsp            // skip red zone.
  cpu_ll_exc_push %rbx, CPU_NR_CRE, %rax   // copy frame start from interrupt
                                           // stack to thread stack.
  movq CPU_LEF_EXC_RAX(%rbx), %rax         // restore registers used
  movq CPU_LEF_EXC_RBX(%rbx), %rbx         // for stack switching.
  pushq $\vector                           // complete exception frame.
  cpu_ll_exc_store_registers
  movq %rsp, %rbx                          // save frame.
.endm

.macro cpu_ll_exc_leave
  movq %rbx, %rsp        // restore stack.
  call thread_schedule   // schedule threads.
  cpu_ll_exc_load_registers
  iretq
.endm

.macro cpu_ll_exc_handle vector
.cfi_undefined 16
  cpu_ll_exc_enter \vector
  movq %rbx, %rdi
  andq $(~(CPU_DATA_ALIGN - 1)), %rsp
  call cpu_exc_main
  cpu_ll_exc_leave
.endm

.macro cpu_ll_intr_handle vector
  cpu_ll_exc_enter \vector
  call cpu_get_intr_stack_ptr
  movq %rax, %rsp   // switch to interrupt stack.
  movq %rbx, %rdi
  call cpu_intr_main
  cpu_ll_exc_leave
.endm

#else   // __LP64__

// Size used to store the segment registers, the vector and the error code.
#define CPU_LEF_SEGS_VEC_ERR   \
  CPU_LEF_OFFSET (CPU_EXC_FRAME_DS, CPU_EXC_FRAME_ERROR + 1)

.macro cpu_ll_exc_store_registers
  pushl %gs
  pushl %fs
  pushl %es
  pushl %ds
  pushl %edi
  pushl %esi
  pushl %ebp
  pushl %edx
  pushl %ecx
  pushl %ebx
  pushl %eax
.endm

// XXX Don't load segment registers for now.
.macro cpu_ll_exc_load_registers
  popl %eax
  popl %ebx
  popl %ecx
  popl %edx
  popl %ebp
  popl %esi
  popl %edi
  addl $CPU_LEF_SEGS_VEC_ERR, %esp   /* skip segment registers,
                                      * vector and error. */
.endm

.macro cpu_ll_exc_enter vector
  pushl $\vector
  cpu_ll_exc_store_registers
  movl %esp, %ebx   // save frame.
.endm

.macro cpu_ll_exc_align_stack
  andl $(~(CPU_DATA_ALIGN - 1)), %esp
.endm

.macro cpu_ll_exc_leave
  movl %ebx, %esp        // restore stack.
  call thread_schedule   // schedule threads.
  cpu_ll_exc_load_registers
  iretl
.endm

.macro cpu_ll_exc_handle vector
.cfi_undefined 8
  cpu_ll_exc_enter \vector
  cpu_ll_exc_align_stack
  pushl %ebx
  call cpu_exc_main
  cpu_ll_exc_leave
.endm

.macro cpu_ll_intr_handle vector
  cpu_ll_exc_enter \vector
  call cpu_get_intr_stack_ptr
  movl %eax, %esp   // switch to interrupt stack.
  pushl %ebx
  call cpu_intr_main
  cpu_ll_exc_leave
.endm

#endif

#define CPU_LL_EXC_HANDLER(vector, name)   \
ASM_ENTRY (name)   \
.cfi_startproc;   \
  push $0;   \
  cpu_ll_exc_handle vector;   \
.cfi_endproc;   \
ASM_END (name)

#define CPU_LL_EXC_HANDLER_WITH_ERROR(vector, name)   \
ASM_ENTRY (name)   \
.cfi_startproc;   \
  cpu_ll_exc_handle vector;   \
.cfi_endproc;   \
ASM_END (name)

#define CPU_LL_INTR_HANDLER(vector, name)   \
ASM_ENTRY (name)   \
.cfi_startproc;   \
  push $0;   \
  cpu_ll_intr_handle vector;   \
.cfi_endproc;   \
ASM_END (name)

// Low level handlers for architectural exceptions.
CPU_LL_EXC_HANDLER (CPU_EXC_DE, cpu_ll_exc_divide_error)
CPU_LL_EXC_HANDLER (CPU_EXC_DB, cpu_ll_exc_debug)
CPU_LL_INTR_HANDLER (CPU_EXC_NMI, cpu_ll_exc_nmi)
CPU_LL_EXC_HANDLER (CPU_EXC_BP, cpu_ll_exc_breakpoint)
CPU_LL_EXC_HANDLER (CPU_EXC_OF, cpu_ll_exc_overflow)
CPU_LL_EXC_HANDLER (CPU_EXC_BR, cpu_ll_exc_bound_range)
CPU_LL_EXC_HANDLER (CPU_EXC_UD, cpu_ll_exc_undefined_opcode)
CPU_LL_EXC_HANDLER (CPU_EXC_NM, cpu_ll_exc_no_math_coprocessor)
CPU_LL_EXC_HANDLER_WITH_ERROR (CPU_EXC_DF, cpu_ll_exc_double_fault)
CPU_LL_EXC_HANDLER_WITH_ERROR (CPU_EXC_TS, cpu_ll_exc_invalid_tss)
CPU_LL_EXC_HANDLER_WITH_ERROR (CPU_EXC_NP, cpu_ll_exc_segment_not_present)
CPU_LL_EXC_HANDLER_WITH_ERROR (CPU_EXC_SS, cpu_ll_exc_stack_segment_fault)
CPU_LL_EXC_HANDLER_WITH_ERROR (CPU_EXC_GP, cpu_ll_exc_general_protection)
CPU_LL_EXC_HANDLER_WITH_ERROR (CPU_EXC_PF, cpu_ll_exc_page_fault)
CPU_LL_EXC_HANDLER (CPU_EXC_MF, cpu_ll_exc_math_fault)
CPU_LL_EXC_HANDLER_WITH_ERROR (CPU_EXC_AC, cpu_ll_exc_alignment_check)
CPU_LL_INTR_HANDLER (CPU_EXC_MC, cpu_ll_exc_machine_check)
CPU_LL_EXC_HANDLER (CPU_EXC_XM, cpu_ll_exc_simd_fp_exception)

/*
 * Low level handlers for reserved exceptions.
 *
 * These exceptions should normally never occur, but have handlers ready just
 * in case.
 */
CPU_LL_EXC_HANDLER (9, cpu_ll_exc_9)
CPU_LL_EXC_HANDLER (15, cpu_ll_exc_15)
CPU_LL_EXC_HANDLER (20, cpu_ll_exc_20)
CPU_LL_EXC_HANDLER (21, cpu_ll_exc_21)
CPU_LL_EXC_HANDLER (22, cpu_ll_exc_22)
CPU_LL_EXC_HANDLER (23, cpu_ll_exc_23)
CPU_LL_EXC_HANDLER (24, cpu_ll_exc_24)
CPU_LL_EXC_HANDLER (25, cpu_ll_exc_25)
CPU_LL_EXC_HANDLER (26, cpu_ll_exc_26)
CPU_LL_EXC_HANDLER (27, cpu_ll_exc_27)
CPU_LL_EXC_HANDLER (28, cpu_ll_exc_28)
CPU_LL_EXC_HANDLER (29, cpu_ll_exc_29)
CPU_LL_EXC_HANDLER (30, cpu_ll_exc_30)
CPU_LL_EXC_HANDLER (31, cpu_ll_exc_31)

// Generic low level interrupt handlers.
CPU_LL_INTR_HANDLER (32, cpu_ll_exc_32)
CPU_LL_INTR_HANDLER (33, cpu_ll_exc_33)
CPU_LL_INTR_HANDLER (34, cpu_ll_exc_34)
CPU_LL_INTR_HANDLER (35, cpu_ll_exc_35)
CPU_LL_INTR_HANDLER (36, cpu_ll_exc_36)
CPU_LL_INTR_HANDLER (37, cpu_ll_exc_37)
CPU_LL_INTR_HANDLER (38, cpu_ll_exc_38)
CPU_LL_INTR_HANDLER (39, cpu_ll_exc_39)
CPU_LL_INTR_HANDLER (40, cpu_ll_exc_40)
CPU_LL_INTR_HANDLER (41, cpu_ll_exc_41)
CPU_LL_INTR_HANDLER (42, cpu_ll_exc_42)
CPU_LL_INTR_HANDLER (43, cpu_ll_exc_43)
CPU_LL_INTR_HANDLER (44, cpu_ll_exc_44)
CPU_LL_INTR_HANDLER (45, cpu_ll_exc_45)
CPU_LL_INTR_HANDLER (46, cpu_ll_exc_46)
CPU_LL_INTR_HANDLER (47, cpu_ll_exc_47)
CPU_LL_INTR_HANDLER (48, cpu_ll_exc_48)
CPU_LL_INTR_HANDLER (49, cpu_ll_exc_49)
CPU_LL_INTR_HANDLER (50, cpu_ll_exc_50)
CPU_LL_INTR_HANDLER (51, cpu_ll_exc_51)
CPU_LL_INTR_HANDLER (52, cpu_ll_exc_52)
CPU_LL_INTR_HANDLER (53, cpu_ll_exc_53)
CPU_LL_INTR_HANDLER (54, cpu_ll_exc_54)
CPU_LL_INTR_HANDLER (55, cpu_ll_exc_55)
CPU_LL_INTR_HANDLER (56, cpu_ll_exc_56)
CPU_LL_INTR_HANDLER (57, cpu_ll_exc_57)
CPU_LL_INTR_HANDLER (58, cpu_ll_exc_58)
CPU_LL_INTR_HANDLER (59, cpu_ll_exc_59)
CPU_LL_INTR_HANDLER (60, cpu_ll_exc_60)
CPU_LL_INTR_HANDLER (61, cpu_ll_exc_61)
CPU_LL_INTR_HANDLER (62, cpu_ll_exc_62)
CPU_LL_INTR_HANDLER (63, cpu_ll_exc_63)
CPU_LL_INTR_HANDLER (64, cpu_ll_exc_64)
CPU_LL_INTR_HANDLER (65, cpu_ll_exc_65)
CPU_LL_INTR_HANDLER (66, cpu_ll_exc_66)
CPU_LL_INTR_HANDLER (67, cpu_ll_exc_67)
CPU_LL_INTR_HANDLER (68, cpu_ll_exc_68)
CPU_LL_INTR_HANDLER (69, cpu_ll_exc_69)
CPU_LL_INTR_HANDLER (70, cpu_ll_exc_70)
CPU_LL_INTR_HANDLER (71, cpu_ll_exc_71)
CPU_LL_INTR_HANDLER (72, cpu_ll_exc_72)
CPU_LL_INTR_HANDLER (73, cpu_ll_exc_73)
CPU_LL_INTR_HANDLER (74, cpu_ll_exc_74)
CPU_LL_INTR_HANDLER (75, cpu_ll_exc_75)
CPU_LL_INTR_HANDLER (76, cpu_ll_exc_76)
CPU_LL_INTR_HANDLER (77, cpu_ll_exc_77)
CPU_LL_INTR_HANDLER (78, cpu_ll_exc_78)
CPU_LL_INTR_HANDLER (79, cpu_ll_exc_79)
CPU_LL_INTR_HANDLER (80, cpu_ll_exc_80)
CPU_LL_INTR_HANDLER (81, cpu_ll_exc_81)
CPU_LL_INTR_HANDLER (82, cpu_ll_exc_82)
CPU_LL_INTR_HANDLER (83, cpu_ll_exc_83)
CPU_LL_INTR_HANDLER (84, cpu_ll_exc_84)
CPU_LL_INTR_HANDLER (85, cpu_ll_exc_85)
CPU_LL_INTR_HANDLER (86, cpu_ll_exc_86)
CPU_LL_INTR_HANDLER (87, cpu_ll_exc_87)
CPU_LL_INTR_HANDLER (88, cpu_ll_exc_88)
CPU_LL_INTR_HANDLER (89, cpu_ll_exc_89)
CPU_LL_INTR_HANDLER (90, cpu_ll_exc_90)
CPU_LL_INTR_HANDLER (91, cpu_ll_exc_91)
CPU_LL_INTR_HANDLER (92, cpu_ll_exc_92)
CPU_LL_INTR_HANDLER (93, cpu_ll_exc_93)
CPU_LL_INTR_HANDLER (94, cpu_ll_exc_94)
CPU_LL_INTR_HANDLER (95, cpu_ll_exc_95)
CPU_LL_INTR_HANDLER (96, cpu_ll_exc_96)
CPU_LL_INTR_HANDLER (97, cpu_ll_exc_97)
CPU_LL_INTR_HANDLER (98, cpu_ll_exc_98)
CPU_LL_INTR_HANDLER (99, cpu_ll_exc_99)
CPU_LL_INTR_HANDLER (100, cpu_ll_exc_100)
CPU_LL_INTR_HANDLER (101, cpu_ll_exc_101)
CPU_LL_INTR_HANDLER (102, cpu_ll_exc_102)
CPU_LL_INTR_HANDLER (103, cpu_ll_exc_103)
CPU_LL_INTR_HANDLER (104, cpu_ll_exc_104)
CPU_LL_INTR_HANDLER (105, cpu_ll_exc_105)
CPU_LL_INTR_HANDLER (106, cpu_ll_exc_106)
CPU_LL_INTR_HANDLER (107, cpu_ll_exc_107)
CPU_LL_INTR_HANDLER (108, cpu_ll_exc_108)
CPU_LL_INTR_HANDLER (109, cpu_ll_exc_109)
CPU_LL_INTR_HANDLER (110, cpu_ll_exc_110)
CPU_LL_INTR_HANDLER (111, cpu_ll_exc_111)
CPU_LL_INTR_HANDLER (112, cpu_ll_exc_112)
CPU_LL_INTR_HANDLER (113, cpu_ll_exc_113)
CPU_LL_INTR_HANDLER (114, cpu_ll_exc_114)
CPU_LL_INTR_HANDLER (115, cpu_ll_exc_115)
CPU_LL_INTR_HANDLER (116, cpu_ll_exc_116)
CPU_LL_INTR_HANDLER (117, cpu_ll_exc_117)
CPU_LL_INTR_HANDLER (118, cpu_ll_exc_118)
CPU_LL_INTR_HANDLER (119, cpu_ll_exc_119)
CPU_LL_INTR_HANDLER (120, cpu_ll_exc_120)
CPU_LL_INTR_HANDLER (121, cpu_ll_exc_121)
CPU_LL_INTR_HANDLER (122, cpu_ll_exc_122)
CPU_LL_INTR_HANDLER (123, cpu_ll_exc_123)
CPU_LL_INTR_HANDLER (124, cpu_ll_exc_124)
CPU_LL_INTR_HANDLER (125, cpu_ll_exc_125)
CPU_LL_INTR_HANDLER (126, cpu_ll_exc_126)
CPU_LL_INTR_HANDLER (127, cpu_ll_exc_127)
CPU_LL_INTR_HANDLER (128, cpu_ll_exc_128)
CPU_LL_INTR_HANDLER (129, cpu_ll_exc_129)
CPU_LL_INTR_HANDLER (130, cpu_ll_exc_130)
CPU_LL_INTR_HANDLER (131, cpu_ll_exc_131)
CPU_LL_INTR_HANDLER (132, cpu_ll_exc_132)
CPU_LL_INTR_HANDLER (133, cpu_ll_exc_133)
CPU_LL_INTR_HANDLER (134, cpu_ll_exc_134)
CPU_LL_INTR_HANDLER (135, cpu_ll_exc_135)
CPU_LL_INTR_HANDLER (136, cpu_ll_exc_136)
CPU_LL_INTR_HANDLER (137, cpu_ll_exc_137)
CPU_LL_INTR_HANDLER (138, cpu_ll_exc_138)
CPU_LL_INTR_HANDLER (139, cpu_ll_exc_139)
CPU_LL_INTR_HANDLER (140, cpu_ll_exc_140)
CPU_LL_INTR_HANDLER (141, cpu_ll_exc_141)
CPU_LL_INTR_HANDLER (142, cpu_ll_exc_142)
CPU_LL_INTR_HANDLER (143, cpu_ll_exc_143)
CPU_LL_INTR_HANDLER (144, cpu_ll_exc_144)
CPU_LL_INTR_HANDLER (145, cpu_ll_exc_145)
CPU_LL_INTR_HANDLER (146, cpu_ll_exc_146)
CPU_LL_INTR_HANDLER (147, cpu_ll_exc_147)
CPU_LL_INTR_HANDLER (148, cpu_ll_exc_148)
CPU_LL_INTR_HANDLER (149, cpu_ll_exc_149)
CPU_LL_INTR_HANDLER (150, cpu_ll_exc_150)
CPU_LL_INTR_HANDLER (151, cpu_ll_exc_151)
CPU_LL_INTR_HANDLER (152, cpu_ll_exc_152)
CPU_LL_INTR_HANDLER (153, cpu_ll_exc_153)
CPU_LL_INTR_HANDLER (154, cpu_ll_exc_154)
CPU_LL_INTR_HANDLER (155, cpu_ll_exc_155)
CPU_LL_INTR_HANDLER (156, cpu_ll_exc_156)
CPU_LL_INTR_HANDLER (157, cpu_ll_exc_157)
CPU_LL_INTR_HANDLER (158, cpu_ll_exc_158)
CPU_LL_INTR_HANDLER (159, cpu_ll_exc_159)
CPU_LL_INTR_HANDLER (160, cpu_ll_exc_160)
CPU_LL_INTR_HANDLER (161, cpu_ll_exc_161)
CPU_LL_INTR_HANDLER (162, cpu_ll_exc_162)
CPU_LL_INTR_HANDLER (163, cpu_ll_exc_163)
CPU_LL_INTR_HANDLER (164, cpu_ll_exc_164)
CPU_LL_INTR_HANDLER (165, cpu_ll_exc_165)
CPU_LL_INTR_HANDLER (166, cpu_ll_exc_166)
CPU_LL_INTR_HANDLER (167, cpu_ll_exc_167)
CPU_LL_INTR_HANDLER (168, cpu_ll_exc_168)
CPU_LL_INTR_HANDLER (169, cpu_ll_exc_169)
CPU_LL_INTR_HANDLER (170, cpu_ll_exc_170)
CPU_LL_INTR_HANDLER (171, cpu_ll_exc_171)
CPU_LL_INTR_HANDLER (172, cpu_ll_exc_172)
CPU_LL_INTR_HANDLER (173, cpu_ll_exc_173)
CPU_LL_INTR_HANDLER (174, cpu_ll_exc_174)
CPU_LL_INTR_HANDLER (175, cpu_ll_exc_175)
CPU_LL_INTR_HANDLER (176, cpu_ll_exc_176)
CPU_LL_INTR_HANDLER (177, cpu_ll_exc_177)
CPU_LL_INTR_HANDLER (178, cpu_ll_exc_178)
CPU_LL_INTR_HANDLER (179, cpu_ll_exc_179)
CPU_LL_INTR_HANDLER (180, cpu_ll_exc_180)
CPU_LL_INTR_HANDLER (181, cpu_ll_exc_181)
CPU_LL_INTR_HANDLER (182, cpu_ll_exc_182)
CPU_LL_INTR_HANDLER (183, cpu_ll_exc_183)
CPU_LL_INTR_HANDLER (184, cpu_ll_exc_184)
CPU_LL_INTR_HANDLER (185, cpu_ll_exc_185)
CPU_LL_INTR_HANDLER (186, cpu_ll_exc_186)
CPU_LL_INTR_HANDLER (187, cpu_ll_exc_187)
CPU_LL_INTR_HANDLER (188, cpu_ll_exc_188)
CPU_LL_INTR_HANDLER (189, cpu_ll_exc_189)
CPU_LL_INTR_HANDLER (190, cpu_ll_exc_190)
CPU_LL_INTR_HANDLER (191, cpu_ll_exc_191)
CPU_LL_INTR_HANDLER (192, cpu_ll_exc_192)
CPU_LL_INTR_HANDLER (193, cpu_ll_exc_193)
CPU_LL_INTR_HANDLER (194, cpu_ll_exc_194)
CPU_LL_INTR_HANDLER (195, cpu_ll_exc_195)
CPU_LL_INTR_HANDLER (196, cpu_ll_exc_196)
CPU_LL_INTR_HANDLER (197, cpu_ll_exc_197)
CPU_LL_INTR_HANDLER (198, cpu_ll_exc_198)
CPU_LL_INTR_HANDLER (199, cpu_ll_exc_199)
CPU_LL_INTR_HANDLER (200, cpu_ll_exc_200)
CPU_LL_INTR_HANDLER (201, cpu_ll_exc_201)
CPU_LL_INTR_HANDLER (202, cpu_ll_exc_202)
CPU_LL_INTR_HANDLER (203, cpu_ll_exc_203)
CPU_LL_INTR_HANDLER (204, cpu_ll_exc_204)
CPU_LL_INTR_HANDLER (205, cpu_ll_exc_205)
CPU_LL_INTR_HANDLER (206, cpu_ll_exc_206)
CPU_LL_INTR_HANDLER (207, cpu_ll_exc_207)
CPU_LL_INTR_HANDLER (208, cpu_ll_exc_208)
CPU_LL_INTR_HANDLER (209, cpu_ll_exc_209)
CPU_LL_INTR_HANDLER (210, cpu_ll_exc_210)
CPU_LL_INTR_HANDLER (211, cpu_ll_exc_211)
CPU_LL_INTR_HANDLER (212, cpu_ll_exc_212)
CPU_LL_INTR_HANDLER (213, cpu_ll_exc_213)
CPU_LL_INTR_HANDLER (214, cpu_ll_exc_214)
CPU_LL_INTR_HANDLER (215, cpu_ll_exc_215)
CPU_LL_INTR_HANDLER (216, cpu_ll_exc_216)
CPU_LL_INTR_HANDLER (217, cpu_ll_exc_217)
CPU_LL_INTR_HANDLER (218, cpu_ll_exc_218)
CPU_LL_INTR_HANDLER (219, cpu_ll_exc_219)
CPU_LL_INTR_HANDLER (220, cpu_ll_exc_220)
CPU_LL_INTR_HANDLER (221, cpu_ll_exc_221)
CPU_LL_INTR_HANDLER (222, cpu_ll_exc_222)
CPU_LL_INTR_HANDLER (223, cpu_ll_exc_223)
CPU_LL_INTR_HANDLER (224, cpu_ll_exc_224)
CPU_LL_INTR_HANDLER (225, cpu_ll_exc_225)
CPU_LL_INTR_HANDLER (226, cpu_ll_exc_226)
CPU_LL_INTR_HANDLER (227, cpu_ll_exc_227)
CPU_LL_INTR_HANDLER (228, cpu_ll_exc_228)
CPU_LL_INTR_HANDLER (229, cpu_ll_exc_229)
CPU_LL_INTR_HANDLER (230, cpu_ll_exc_230)
CPU_LL_INTR_HANDLER (231, cpu_ll_exc_231)
CPU_LL_INTR_HANDLER (232, cpu_ll_exc_232)
CPU_LL_INTR_HANDLER (233, cpu_ll_exc_233)
CPU_LL_INTR_HANDLER (234, cpu_ll_exc_234)
CPU_LL_INTR_HANDLER (235, cpu_ll_exc_235)
CPU_LL_INTR_HANDLER (236, cpu_ll_exc_236)
CPU_LL_INTR_HANDLER (237, cpu_ll_exc_237)
CPU_LL_INTR_HANDLER (238, cpu_ll_exc_238)
CPU_LL_INTR_HANDLER (239, cpu_ll_exc_239)
CPU_LL_INTR_HANDLER (240, cpu_ll_exc_240)
CPU_LL_INTR_HANDLER (241, cpu_ll_exc_241)
CPU_LL_INTR_HANDLER (242, cpu_ll_exc_242)
CPU_LL_INTR_HANDLER (243, cpu_ll_exc_243)
CPU_LL_INTR_HANDLER (244, cpu_ll_exc_244)
CPU_LL_INTR_HANDLER (245, cpu_ll_exc_245)
CPU_LL_INTR_HANDLER (246, cpu_ll_exc_246)
CPU_LL_INTR_HANDLER (247, cpu_ll_exc_247)
CPU_LL_INTR_HANDLER (248, cpu_ll_exc_248)
CPU_LL_INTR_HANDLER (249, cpu_ll_exc_249)
CPU_LL_INTR_HANDLER (250, cpu_ll_exc_250)
CPU_LL_INTR_HANDLER (251, cpu_ll_exc_251)
CPU_LL_INTR_HANDLER (252, cpu_ll_exc_252)
CPU_LL_INTR_HANDLER (253, cpu_ll_exc_253)
CPU_LL_INTR_HANDLER (254, cpu_ll_exc_254)
CPU_LL_INTR_HANDLER (255, cpu_ll_exc_255)

#ifdef __LP64__
  #define CPU_LL_EXC_HANDLER_ADDR(name)   .quad name
#else
  #define CPU_LL_EXC_HANDLER_ADDR(name)   .long name
#endif

.section INIT_DATA_SECTION

// See the C declaration.
ASM_DATA (cpu_ll_exc_handler_addrs)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_divide_error)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_debug)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_nmi)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_breakpoint)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_overflow)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_bound_range)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_undefined_opcode)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_no_math_coprocessor)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_double_fault)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_9)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_invalid_tss)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_segment_not_present)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_stack_segment_fault)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_general_protection)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_page_fault)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_15)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_math_fault)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_alignment_check)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_machine_check)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_simd_fp_exception)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_20)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_21)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_22)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_23)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_24)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_25)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_26)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_27)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_28)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_29)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_30)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_31)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_32)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_33)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_34)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_35)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_36)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_37)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_38)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_39)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_40)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_41)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_42)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_43)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_44)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_45)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_46)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_47)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_48)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_49)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_50)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_51)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_52)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_53)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_54)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_55)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_56)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_57)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_58)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_59)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_60)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_61)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_62)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_63)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_64)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_65)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_66)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_67)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_68)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_69)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_70)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_71)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_72)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_73)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_74)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_75)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_76)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_77)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_78)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_79)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_80)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_81)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_82)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_83)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_84)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_85)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_86)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_87)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_88)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_89)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_90)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_91)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_92)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_93)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_94)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_95)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_96)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_97)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_98)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_99)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_100)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_101)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_102)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_103)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_104)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_105)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_106)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_107)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_108)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_109)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_110)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_111)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_112)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_113)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_114)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_115)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_116)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_117)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_118)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_119)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_120)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_121)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_122)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_123)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_124)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_125)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_126)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_127)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_128)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_129)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_130)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_131)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_132)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_133)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_134)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_135)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_136)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_137)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_138)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_139)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_140)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_141)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_142)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_143)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_144)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_145)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_146)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_147)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_148)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_149)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_150)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_151)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_152)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_153)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_154)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_155)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_156)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_157)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_158)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_159)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_160)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_161)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_162)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_163)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_164)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_165)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_166)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_167)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_168)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_169)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_170)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_171)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_172)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_173)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_174)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_175)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_176)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_177)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_178)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_179)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_180)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_181)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_182)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_183)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_184)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_185)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_186)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_187)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_188)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_189)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_190)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_191)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_192)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_193)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_194)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_195)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_196)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_197)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_198)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_199)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_200)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_201)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_202)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_203)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_204)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_205)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_206)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_207)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_208)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_209)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_210)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_211)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_212)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_213)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_214)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_215)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_216)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_217)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_218)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_219)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_220)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_221)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_222)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_223)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_224)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_225)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_226)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_227)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_228)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_229)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_230)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_231)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_232)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_233)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_234)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_235)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_236)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_237)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_238)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_239)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_240)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_241)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_242)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_243)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_244)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_245)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_246)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_247)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_248)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_249)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_250)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_251)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_252)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_253)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_254)
  CPU_LL_EXC_HANDLER_ADDR (cpu_ll_exc_255)
ASM_END (cpu_ll_exc_handler_addrs)

ASM_ENTRY (cpu_load_gdt)
.cfi_startproc
#ifdef __LP64__
  lgdt (%rdi)
#else
  movl 4(%esp), %eax
  lgdt (%eax)
#endif

  movl $CPU_GDT_SEL_DATA, %eax
  movl %eax, %ds
  movl %eax, %es
  movl %eax, %ss

 // Alter the stack to reload the code segment using a far return.
#ifdef __LP64__
  popq %rax
  pushq $CPU_GDT_SEL_CODE
  pushq %rax
  lretq
#else
  popl %eax
  pushl $CPU_GDT_SEL_CODE
  pushl %eax
  lret
#endif
.cfi_endproc
ASM_END (cpu_load_gdt)

ASM_ENTRY (cpu_unw_mctx_save)
.cfi_startproc
#ifdef __LP64__
  movq %rbx, 24(%rdi)
  movq %rbp, 48(%rdi)
  movq %r12, 96(%rdi)
  movq %r13, (13 * 8)(%rdi)
  movq %r14, (14 * 8)(%rdi)
  movq %r15, (15 * 8)(%rdi)
  leaq 8(%rsp), %rdx
  movq %rdx, 56(%rdi)
  movq (%rsp), %rdx
  movq %rdx, (16 * 8)(%rdi)
#else
  movl 4(%esp), %eax
  movl %ebx, 12(%eax)
  movl %esi, 24(%eax)
  movl %edi, 28(%eax)
  movl %ebp, 20(%eax)
  leal 4(%esp), %ecx
  movl %ecx, 16(%eax)
  movl (%esp), %ecx
  movl %ecx, 32(%eax)
#endif
  ret
.cfi_endproc
ASM_END (cpu_unw_mctx_save)

ASM_ENTRY (cpu_unw_mctx_jmp)
.cfi_startproc
#ifdef __LP64__
  movq (16 * 8)(%rdi), %rax   # New PC.
  movq 56(%rdi), %rsp         # Restore stack pointer.
  pushq %rax                  # Set new return address.
  movq %rsi, %rax
  movq 8(%rdi), %rdx
  movq 16(%rdi), %rcx
  movq 24(%rdi), %rbx
  movq 32(%rdi), %rsi
  movq 48(%rdi), %rbp
  movq (8 * 8) (%rdi), %r8
  movq (9 * 8) (%rdi), %r9
  movq (10 * 8)(%rdi), %r10
  movq (11 * 8)(%rdi), %r11
  movq (12 * 8)(%rdi), %r12
  movq (13 * 8)(%rdi), %r13
  movq (14 * 8)(%rdi), %r14
  movq (15 * 8)(%rdi), %r15
  movq 40(%rdi), %rdi
#else
  movl 4(%esp), %ecx
  movl 8(%esp), %eax
  movl 32(%ecx), %edx   # New PC.
  movl 16(%ecx), %esp   # Restore stack pointer.
  pushl %edx            # Set new return address.
  movl 8(%ecx), %edx
  movl 12(%ecx), %ebx
  movl 20(%ecx), %ebp
  movl 24(%ecx), %esi
  movl 28(%ecx), %edi
  movl 4(%ecx), %ecx
#endif
  ret
.cfi_endproc
ASM_END (cpu_unw_mctx_jmp)

ASM_ENTRY (cpu_port_swap)
.cfi_startproc
#ifdef __LP64__
  # Store registers required by the ABI.
  pushq %rbp
  pushq %rbx
  pushq %r12
  pushq %r13
  pushq %r14
  pushq %r15
  # Save current stack and switch to new one.
  movq 0(%rdi), %rcx
  movq %rsp, 0(%rdi)
  movq %rcx, %rsp
  # Save old port and load entry point arguments.
  movq 16(%rdi), %rsi
  movq 8(%rdi), %rcx
  movq %rdx, 8(%rdi)
  movq %rcx, %rdi
  # Jump to entry point.
  jmp *%rdx
#else
  movl %esp, %ecx
  # Store registers required by the ABI.
  pushl %ebp
  pushl %ebx
  pushl %edi
  pushl %esi
  # Save current stack and switch to new one.
  movl 4(%ecx), %eax
  movl 0(%eax), %edx
  movl %esp, 0(%eax)
  movl %edx, %esp
  # Save old port and load entry point arguments.
  movl 8(%eax), %edx
  movl 4(%eax), %eax
  movl 12(%ecx), %ecx
  # Jump to entry point.
  jmp *%ecx
#endif
.cfi_endproc
ASM_END (cpu_port_swap)

ASM_ENTRY (cpu_port_return)
.cfi_startproc
#ifdef __LP64__
  movq %rdi, %rsp
  movq %rsi, %rax
  popq %r15
  popq %r14
  popq %r13
  popq %r12
  popq %rbx
  popq %rbp
#else
  movl 8(%esp), %eax
  movl 4(%esp), %esp
  popl %esi
  popl %edi
  popl %ebx
  popl %ebp
#endif
  ret
.cfi_endproc
ASM_END (cpu_port_return)
